"""
平板端实时分析结果获取示例

功能：
1. 演示如何在平板端获取实时分析结果
2. 实现智能轮询策略，根据分析状态调整请求频率
3. 处理不同的分析状态（processing/completed/error/no_data）
4. 提供错误重试和连接恢复机制
5. 优化网络请求，减少不必要的流量消耗

使用方法：
- 在平板应用中集成此客户端类
- 调用start_monitoring()开始监控
- 通过回调函数处理分析结果
- 调用stop_monitoring()停止监控

原理：
- 使用状态机管理不同的分析阶段
- 根据服务器返回的状态动态调整轮询频率
- 实现指数退避重试机制
- 支持断线重连和网络异常处理
"""

import asyncio
import aiohttp
import json
import logging
from datetime import datetime, timedelta
from typing import Dict, Any, Optional, Callable, List
from enum import Enum
import time

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class AnalysisStatus(Enum):
    """分析状态枚举"""
    NO_DATA = "no_data"
    PROCESSING = "processing"
    COMPLETED = "completed"
    ERROR = "error"

class RealtimeAnalysisClient:
    """实时分析结果获取客户端"""
    
    def __init__(self, 
                 base_url: str = "http://localhost:8000",
                 session_id: str = None,
                 room_id: str = None,
                 user_id: str = None):
        """
        初始化客户端
        
        Args:
            base_url: 服务器基础URL
            session_id: 会话ID
            room_id: 房间ID（可选）
            user_id: 用户ID（可选）
        """
        self.base_url = base_url.rstrip('/')
        self.session_id = session_id
        self.room_id = room_id
        self.user_id = user_id
        
        # 轮询配置
        self.polling_intervals = {
            AnalysisStatus.NO_DATA: 5.0,      # 无数据时，5秒查询一次
            AnalysisStatus.PROCESSING: 2.0,   # 处理中时，2秒查询一次
            AnalysisStatus.COMPLETED: 3.0,    # 完成后，3秒查询一次（获取新结果）
            AnalysisStatus.ERROR: 10.0        # 错误时，10秒后重试
        }
        
        # 状态管理
        self.current_status = AnalysisStatus.NO_DATA
        self.is_monitoring = False
        self.monitoring_task = None
        
        # 重试配置
        self.max_retries = 3
        self.retry_delay_base = 1.0  # 基础重试延迟（秒）
        self.consecutive_errors = 0
        
        # 回调函数
        self.on_analysis_result: Optional[Callable] = None
        self.on_status_change: Optional[Callable] = None
        self.on_error: Optional[Callable] = None
        
        # HTTP会话
        self.session: Optional[aiohttp.ClientSession] = None
        
        # 统计信息
        self.stats = {
            'total_requests': 0,
            'successful_requests': 0,
            'failed_requests': 0,
            'last_successful_time': None,
            'last_analysis_result': None
        }
    
    async def __aenter__(self):
        """异步上下文管理器入口"""
        await self.start_session()
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """异步上下文管理器出口"""
        await self.close_session()
    
    async def start_session(self):
        """启动HTTP会话"""
        if not self.session:
            timeout = aiohttp.ClientTimeout(total=30, connect=10)
            self.session = aiohttp.ClientSession(timeout=timeout)
    
    async def close_session(self):
        """关闭HTTP会话"""
        if self.session:
            await self.session.close()
            self.session = None
    
    def set_callbacks(self, 
                     on_analysis_result: Optional[Callable] = None,
                     on_status_change: Optional[Callable] = None,
                     on_error: Optional[Callable] = None):
        """
        设置回调函数
        
        Args:
            on_analysis_result: 分析结果回调 (result: Dict)
            on_status_change: 状态变化回调 (old_status: str, new_status: str)
            on_error: 错误回调 (error: Exception, context: str)
        """
        self.on_analysis_result = on_analysis_result
        self.on_status_change = on_status_change
        self.on_error = on_error
    
    async def get_realtime_analysis(self) -> Optional[Dict[str, Any]]:
        """
        获取实时分析结果
        
        Returns:
            分析结果字典或None（如果请求失败）
        """
        if not self.session:
            await self.start_session()
        
        url = f"{self.base_url}/api/tablet/realtime/{self.session_id}"
        params = {}
        
        if self.room_id:
            params['room_id'] = self.room_id
        if self.user_id:
            params['user_id'] = self.user_id
        
        try:
            self.stats['total_requests'] += 1
            
            async with self.session.get(url, params=params) as response:
                if response.status == 200:
                    result = await response.json()
                    self.stats['successful_requests'] += 1
                    self.stats['last_successful_time'] = datetime.now()
                    self.consecutive_errors = 0
                    return result
                else:
                    error_text = await response.text()
                    logger.error(f"HTTP错误 {response.status}: {error_text}")
                    self.stats['failed_requests'] += 1
                    return None
                    
        except asyncio.TimeoutError:
            logger.error("请求超时")
            self.stats['failed_requests'] += 1
            self.consecutive_errors += 1
            return None
        except aiohttp.ClientError as e:
            logger.error(f"网络错误: {e}")
            self.stats['failed_requests'] += 1
            self.consecutive_errors += 1
            return None
        except Exception as e:
            logger.error(f"未知错误: {e}")
            self.stats['failed_requests'] += 1
            self.consecutive_errors += 1
            if self.on_error:
                await self.on_error(e, "get_realtime_analysis")
            return None
    
    def _update_status(self, new_status: AnalysisStatus):
        """更新分析状态"""
        if self.current_status != new_status:
            old_status = self.current_status
            self.current_status = new_status
            
            logger.info(f"状态变化: {old_status.value} -> {new_status.value}")
            
            if self.on_status_change:
                asyncio.create_task(self.on_status_change(old_status.value, new_status.value))
    
    def _get_polling_interval(self) -> float:
        """
        获取当前状态的轮询间隔
        
        Returns:
            轮询间隔（秒）
        """
        base_interval = self.polling_intervals[self.current_status]
        
        # 如果连续出错，增加轮询间隔（指数退避）
        if self.consecutive_errors > 0:
            backoff_multiplier = min(2 ** self.consecutive_errors, 8)  # 最大8倍
            return base_interval * backoff_multiplier
        
        return base_interval
    
    async def _process_analysis_result(self, result: Dict[str, Any]):
        """
        处理分析结果
        
        Args:
            result: 服务器返回的分析结果
        """
        if not result:
            return
        
        status_str = result.get('status', 'no_data')
        
        try:
            new_status = AnalysisStatus(status_str)
        except ValueError:
            logger.warning(f"未知状态: {status_str}，默认为no_data")
            new_status = AnalysisStatus.NO_DATA
        
        # 更新状态
        self._update_status(new_status)
        
        # 处理不同状态的结果
        if new_status == AnalysisStatus.COMPLETED:
            # 分析完成，保存结果并触发回调
            self.stats['last_analysis_result'] = result
            
            if self.on_analysis_result:
                await self.on_analysis_result(result)
            
            logger.info(f"获取到分析结果: 睡眠阶段={result.get('sleep_stage')}, "
                       f"置信度={result.get('confidence')}")
        
        elif new_status == AnalysisStatus.PROCESSING:
            # 分析进行中，记录进度信息
            elapsed = result.get('elapsed_seconds', 0)
            estimated = result.get('estimated_completion_seconds', 0)
            
            logger.info(f"分析进行中: 已用时{elapsed:.1f}秒, 预计还需{estimated:.1f}秒")
        
        elif new_status == AnalysisStatus.ERROR:
            # 分析出错，记录错误信息
            error_msg = result.get('error', '未知错误')
            logger.error(f"分析出错: {error_msg}")
            
            if self.on_error:
                error = Exception(error_msg)
                await self.on_error(error, "analysis_error")
        
        elif new_status == AnalysisStatus.NO_DATA:
            # 无数据，等待数据上传
            logger.debug("暂无分析数据，等待数据上传")
    
    async def _monitoring_loop(self):
        """监控循环"""
        logger.info(f"开始监控实时分析结果: session_id={self.session_id}")
        
        while self.is_monitoring:
            try:
                # 获取分析结果
                result = await self.get_realtime_analysis()
                
                # 处理结果
                await self._process_analysis_result(result)
                
                # 计算下次轮询间隔
                interval = self._get_polling_interval()
                
                # 等待下次轮询
                await asyncio.sleep(interval)
                
            except asyncio.CancelledError:
                logger.info("监控任务被取消")
                break
            except Exception as e:
                logger.error(f"监控循环出错: {e}")
                
                if self.on_error:
                    await self.on_error(e, "monitoring_loop")
                
                # 出错后等待一段时间再继续
                await asyncio.sleep(5.0)
    
    async def start_monitoring(self):
        """开始监控"""
        if self.is_monitoring:
            logger.warning("监控已在运行中")
            return
        
        if not self.session_id:
            raise ValueError("session_id不能为空")
        
        await self.start_session()
        
        self.is_monitoring = True
        self.monitoring_task = asyncio.create_task(self._monitoring_loop())
        
        logger.info("实时分析监控已启动")
    
    async def stop_monitoring(self):
        """停止监控"""
        if not self.is_monitoring:
            return
        
        self.is_monitoring = False
        
        if self.monitoring_task:
            self.monitoring_task.cancel()
            try:
                await self.monitoring_task
            except asyncio.CancelledError:
                pass
            self.monitoring_task = None
        
        logger.info("实时分析监控已停止")
    
    def get_stats(self) -> Dict[str, Any]:
        """获取统计信息"""
        return {
            **self.stats,
            'current_status': self.current_status.value,
            'consecutive_errors': self.consecutive_errors,
            'success_rate': (self.stats['successful_requests'] / max(self.stats['total_requests'], 1)) * 100
        }

# 使用示例
async def example_usage():
    """使用示例"""
    
    # 回调函数定义
    async def on_analysis_result(result: Dict[str, Any]):
        """处理分析结果"""
        print(f"🧠 分析结果: {result.get('sleep_stage')} (置信度: {result.get('confidence')})")
        
        # 可以在这里更新UI或保存数据
        frequency_bands = result.get('frequency_bands', {})
        if frequency_bands:
            print(f"   频域分析: Delta={frequency_bands.get('delta', 0):.3f}, "
                  f"Alpha={frequency_bands.get('alpha', 0):.3f}")
    
    async def on_status_change(old_status: str, new_status: str):
        """处理状态变化"""
        print(f"📊 状态变化: {old_status} -> {new_status}")
    
    async def on_error(error: Exception, context: str):
        """处理错误"""
        print(f"❌ 错误 [{context}]: {error}")
    
    # 创建客户端
    client = RealtimeAnalysisClient(
        base_url="http://localhost:8000",
        session_id="test_session_001",
        room_id="room_123",
        user_id="user_456"
    )
    
    # 设置回调函数
    client.set_callbacks(
        on_analysis_result=on_analysis_result,
        on_status_change=on_status_change,
        on_error=on_error
    )
    
    try:
        # 使用异步上下文管理器
        async with client:
            # 开始监控
            await client.start_monitoring()
            
            # 运行30秒
            await asyncio.sleep(30)
            
            # 打印统计信息
            stats = client.get_stats()
            print(f"\n📈 统计信息:")
            print(f"   总请求数: {stats['total_requests']}")
            print(f"   成功率: {stats['success_rate']:.1f}%")
            print(f"   当前状态: {stats['current_status']}")
            
    except KeyboardInterrupt:
        print("\n⏹️  用户中断")
    finally:
        # 停止监控
        await client.stop_monitoring()
        print("✅ 监控已停止")

if __name__ == "__main__":
    # 运行示例
    asyncio.run(example_usage())